#ifndef RoServerModule__h
#define RoServerModule__h


#include <QtNetwork>
#include <QtXml>

#include "romashka.h"
#include "RoModule.h"
#include "RoXmlStream.h"


class RoServerModule:
    public RoAbstractModule
{
    Q_OBJECT
    
public:
    
    typedef RoAbstractModule super;
    
    explicit RoServerModule(QObject * parent = 0, bool logTraffic = false);
    
    ~RoServerModule();
    
    bool connectToNetwork()
        { return connectToNetwork(QHostAddress::Any); }

    /// @group Adapting QTcpServer interface
    /// @{
        QString errorString() const
            { return transport->errorString(); }

        virtual bool isConnected() const
            { return transport->isListening(); }

        QHostAddress serverAddress() const
            { return transport->serverAddress(); }

        quint16 serverPort() const
            { return transport->serverPort(); }
    /// @}

    virtual RoStanzaId sendStanza(RoStanza stanza);

    /// Список клиентов и таблица маршрутизации (без ROUTER!).
    class ClientsDB
    {

    private:

        QMultiMap<RoXmlStream*, QString> data;

    public:

        /// добавить компонент name с потоком stream
        void insert(const QString & name, RoXmlStream * stream)
            { data.insert(stream, name); }

        /// удалить компонент name
        void remove(const QString & name)
            { data.remove(data.key(name)); }

        /// удалить все компоненты на потоке stream
        void removeStreamAndAllItsComponents(RoXmlStream * stream)
            { data.remove(stream); }

        /// проверить, есть ли в сети компонент name
        bool contains(const QString & name) const
            { return data.key(name); }

        /// получить поток для разговора с name. Если 0, то такого компонента нет
        RoXmlStream * stream(const QString & name) const
            { return data.key(name); }

        /// список всех компонентов (без ROUTER!) (повторений теоретически не должно быть)
        QStringList components(RoXmlStream * stream = 0) const
            { return stream ? data.values(stream) : data.values(); }

        /// список всех потоков (возможны повторения!)
        QList<RoXmlStream*> streams() const
            { return data.uniqueKeys(); }

    }; // class ClientsDB

    ClientsDB clients;

public slots:

    /// @group Adapting QTcpServer interface
    /// @{
        bool connectToNetwork(const QHostAddress & address, quint16 port = ROMASHKA_STANDARD_PORT)
            { return transport->listen(address, port); }

        void disconnectFromNetwork()
            { transport->close(); }
    /// @}

protected:

    /// Reimplemented from RoAbstractModule to receive presence stanzas with the source stream.
    virtual void presenceEvent(RoXmlStream * stream, RoInfoStanza stanza);

private:
    
    QPointer<QTcpServer> transport;

    QMap<int /* socket descriptor */, RoXmlStream *> clientStreams;

    virtual void recieve_stanza(RoStanza stanza);

private slots:

    void acceptNewConnection();

    void mournClient();

signals:

    void clientConnected(RoXmlStream *);

}; // class RoServerModule


#endif // RoServerModule__h
